package com.yuanxiao.common.redis.utils;

import com.yuanxiao.common.core.exception.RRException;
import com.yuanxiao.common.core.result.R;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class DistributedLockUtils {

    protected static Logger logger = LoggerFactory.getLogger(DistributedLockUtils.class);

    private final RedissonClient redissonClient;

    public DistributedLockUtils(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 获取多个联合锁
     */
    public static ResourceLock getMultiLock(RedissonClient redissonClient, List<ResourceLock.LockResource> resources) {
        return new ResourceLock(redissonClient, resources);
    }

    /**
     * 获取单个锁
     */
    public static ResourceLock getSingleLock(RedissonClient redissonClient, String lockKey) {
        List<ResourceLock.LockResource> resources = new ArrayList<>();
        resources.add(ResourceLock.LockResource.of(lockKey));
        return new ResourceLock(redissonClient, resources);
    }


    /**
     * 加锁并执行业务逻辑（支持 lambda 表达式，允许抛出异常）
     */
    public static R executeWithLock(RedissonClient redissonClient,
                                    List<ResourceLock.LockResource> resources,
                                    ThrowingRunnable businessLogic) {
        /**
         * 使用 ResourceLock 获取并自动释放锁
         * ResourceLock 实现了 AutoCloseable。并且重写了 close() 方法来释放锁
         * Java 的 try-with-resources 会在 try 块结束时自动调用 close() 方法，即：
         * try (ResourceLock lock = ...) { // <-- 进入 try 时调用了 lock.lock()
         *     ...
         * } // <-- 离开 try 时自动调用 lock.close()，即释放锁
         *
         * 所以，锁在 try 块结束后会自动释放。
         * 即使在执行过程中抛出异常（如 RRException 或其他异常），由于 try-with-resources 的特性，JVM 也会确保 close() 被调用（除非 JVM 崩溃或线程被中断）。
         */
        try (ResourceLock lock = getMultiLock(redissonClient, resources)) {
            logger.info("开始获取分布式锁，锁定资源: {}", resources);
            long startTime = System.currentTimeMillis();

            // lock.lock(); // 获取锁
            // lock.lock() → lock.tryLock(10, 120, TimeUnit.SECONDS)，避免无限等待，最多等 10 秒；一旦获取，锁最多持有 120 秒自动释放
            // 使用 tryLock 设置最大等待时间和持有时间
            if (!lock.tryLock(10, 120, TimeUnit.SECONDS)) {
                // logger.error("获取分布式锁超时");
                throw new RRException("获取分布式锁超时");
            }

            long lockTime = System.currentTimeMillis() - startTime;
            logger.info("成功获取分布式锁，耗时 {} ms", lockTime);

            logger.info("开始执行业务逻辑");
            long businessStartTime = System.currentTimeMillis();

            businessLogic.run(); // 可能抛出异常

            long businessDuration = System.currentTimeMillis() - businessStartTime;
            logger.info("业务逻辑执行完成，耗时 {} ms", businessDuration);

            return R.ok ();
        } catch (Exception e) {
            // 可以记录日志或上报监控
            // logger.error("执行业务逻辑时发生异常", e);
            throw new RRException ("分布式锁内业务执行失败", e);
        }
    }

    /**
     * 函数式接口：允许 run() 方法抛出异常
     */
    @FunctionalInterface
    public interface ThrowingRunnable {
        void run() throws Exception;
    }

}


